package com.bestcem.xm.user.grpc.service;

import cn.hutool.core.lang.ObjectId;
import com.alibaba.fastjson.JSON;
import com.bestcem.bp.xm.user.grpc.v1.services.*;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.component.security.dto.AuthenticationDTO;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.enums.UserSsoStatusEnum;
import com.bestcem.xm.user.grpc.service.converter.AuthGrpcConverter;
import com.bestcem.xm.user.grpc.service.converter.UserPermissionConverter;
import com.bestcem.xm.user.grpc.v1.enums.SsoStatusEnum;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.user.AuthDTO;
import com.bestcem.xm.user.service.dto.user.OrganizationDTO;
import com.bestcem.xm.user.service.dto.user.SsoDTO;
import com.bestcem.xm.user.service.dto.user.UserDTO;
import com.bestcem.xm.user.util.business.UserCacheUtil;
import com.bestcem.xm.user.util.business.UserJwtTokenUtil;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 鉴权的GRPC
 *
 * @author Linked <zhijian.lin@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/8 14:52
 */
@Slf4j
@GrpcService
public class UserAuthGrpcService extends UserAuthServiceGrpc.UserAuthServiceImplBase {

    @Autowired
    private UserCacheUtil userCacheUtil;

    @Resource
    private RolePermissionService rolePermissionService;

    @Resource
    private UserService userService;

    @Resource
    private OrganizationService organizationService;

    @Resource
    private UserJwtTokenUtil tokenUtil;

    @Resource
    private SsoService ssoService;

    @Resource
    private UserBusinessService userBusinessService;

    @Resource
    private AuthenticationService authenticationService;

    @Value("${jwt.refresh-timeout:43200}")
    private Integer refreshTimeout;

    /**
     * 用户鉴权
     *
     * @param request：请求参数
     * @param responseObserver： 响应结果
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/03/08 16:44
     */
    @Override
    public void checkAuth(CheckAuthRequest request,
                          StreamObserver<CheckAuthResponse> responseObserver) {
        CheckAuthResponse.Builder builder = CheckAuthResponse.newBuilder();
        String token = request.getToken();
        Boolean authentication = request.getAuthentication();
        String uri = request.getUri();
        String method = request.getMethod();
        if (StringUtils.isBlank(token)) {
            builder.setStatus(RpcStatusResult.error(ReqErrorCodeEnum.TOKEN_LOST.getCode() + ""));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<AuthenticationDTO> result = authenticationService.checkAuthentication(token, authentication, uri, method);
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        if (Objects.isNull(result.getData().getToken())) {
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        if (Boolean.TRUE.equals(authentication)) {
            builder.setPermission(result.getData().getPermission());
        }
        Token info = UserPermissionConverter.dtoToGrpcToken(result.getData().getToken());
        builder.setToken(info);
        builder.setStatus(RpcStatusResult.success());
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    /**
     * 存储用户的xm_ticket_id缓存
     *
     * @param request          请求参数
     * @param responseObserver 响应结果
     * @return void
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/31 0:29
     */
    @Override
    public void createUserTicketId(CreateUserTicketIdRequest request,
                                   StreamObserver<CreateUserTicketIdResponse> responseObserver) {
        CreateUserTicketIdResponse.Builder builder = CreateUserTicketIdResponse.newBuilder();

        String orgCode = request.getOrgCode();
        String xmTicketId = request.getTicketId();
        String name = request.getName();
        String username = request.getUsername();

        if (StringUtils.isBlank(username)) {
            builder.setStatus(RpcStatusResult.error(AuthErrorCodeEnum.USER_NOT_EXISTS.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        String infoName = String.format(UserCacheKeyConstant.USER_INFO, orgCode, xmTicketId);
        HashMap<String, String> userInfo = new HashMap<>(16);
        userInfo.put("userName", username);
        userInfo.put("name", name);
        userCacheUtil.setEx(infoName, JSON.toJSONString(userInfo), 60, TimeUnit.SECONDS);
        builder.setStatus(RpcStatusResult.success());
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    /**
     * 通过userid获取token以及refresh_token
     *
     * @param request：请求参数
     * @param responseObserver： 响应结果
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/03/08 16:51
     */
    @Override
    public void getTokenByUserId(GetTokenByUserIdRequest request,
                                 StreamObserver<GetTokenByUserIdResponse> responseObserver) {
        GetTokenByUserIdResponse.Builder builder = GetTokenByUserIdResponse.newBuilder();
        // userId 判断
        String userId = request.getUserId();
        if (!ObjectId.isValid(userId)) {
            builder.setStatus(RpcStatusResult.error(ReqErrorCodeEnum.PARAM_LOST.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
        }
        // 用户
        ServiceResult<UserDTO> userResult = userService.getUserByPrimaryKey(userId);
        if (!userResult.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(AuthErrorCodeEnum.USER_NOT_EXISTS.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
        }
        UserDTO userDTO = userResult.getData();
        // 公司
        ServiceResult<OrganizationDTO> serviceResult = organizationService.selectByPrimaryKey(userDTO.getOrgId());
        if (!serviceResult.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(AuthErrorCodeEnum.ORG_NOT_EXISTS.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
        }
        // 套餐是否过期
        OrganizationDTO organization = serviceResult.getData();
        if (organization.getPackageExpireTime().before(new Date())) {
            builder.setStatus(RpcStatusResult.error(AuthErrorCodeEnum.ORG_EXPIRE.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
        }
        AuthDTO authDTO = AuthDTO.builder().
                orgId(organization.getOrgId()).
                orgCode(organization.getCode()).
                userId(userDTO.getUserId()).
                realName(userDTO.getName()).
                avatar(userDTO.getAvatar()).
                packageExpireTime(UserJwtTokenUtil.formatDate(organization.getPackageExpireTime())).
                superRole(userBusinessService.checkSuper(userId, userDTO.getOrgId()).getData()).
                senior(userBusinessService.checkSenior(userId, userDTO.getOrgId()).getData()).
                timeout(refreshTimeout + "").
                build();

        String token = tokenUtil.generateDeliveryToken(authDTO);
        String refreshToken = tokenUtil.generateRefreshToken(organization.getCode(), userId);
        builder.setToken(token);
        builder.setRefreshToken(refreshToken);
        builder.setStatus(RpcStatusResult.success());
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    /**
     * 创建sso用户
     *
     * @param request          请求参数
     * @param responseObserver 响应结果
     * @return void
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/31 1:00
     */
    @Override
    public void getSsoByOrgId(GetSsoByOrgIdRequest request,
                              StreamObserver<GetSsoByOrgIdResponse> responseObserver) {
        GetSsoByOrgIdResponse.Builder builder = GetSsoByOrgIdResponse.newBuilder();
        String orgId = request.getOrgId();
        if (!ObjectId.isValid(orgId)) {
            builder.setStatus(RpcStatusResult.error(ReqErrorCodeEnum.PARAM_FORMAT.getMsg()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        SsoDTO ssoDTO = new SsoDTO();
        ssoDTO.setOrgId(orgId);
        ssoDTO.setStatus(UserSsoStatusEnum.ACTIVATED.getStatus());
        ServiceResult<SsoDTO> ssoDTOServiceResult = ssoService.selectBySelective(ssoDTO);
        SsoDTO sso = ssoDTOServiceResult.getData();

        if (Objects.isNull(sso)) {
            builder.setStatus(RpcStatusResult.error("未找到相关sso信息"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }

        Sso.Builder ssoBuilder = Sso.newBuilder();
        ssoBuilder.setOrgId(sso.getOrgId())
                .setId(sso.getSsoId())
                .setType(sso.getType())
                .setStatus(SsoStatusEnum.SsoStatus.forNumber(sso.getStatus()))
                .setConfig(sso.getConfig());
        builder.setStatus(RpcStatusResult.success())
                .setSso(ssoBuilder.build());
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

    /**
     * 创建sso信息
     *
     * @param request
     * @param responseObserver
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/30 14:25
     */
    @Override
    public void createSso(CreateSsoRequest request, StreamObserver<CreateSsoResponse> responseObserver) {
        // 获取返回对象的构造器
        CreateSsoResponse.Builder builder = CreateSsoResponse.newBuilder();

        // 创建sso信息
        ServiceResult<SsoDTO> result = ssoService.create(AuthGrpcConverter.ssoReqGrpc2Dto(request));

        // 设置返回值
        if (!result.isSuccess()) {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        } else {
            builder.setStatus(RpcStatusResult.success());
            builder.setId(result.getData().getSsoId());
        }

        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
    }

}
